import re

from django_redis import get_redis_connection
from rest_framework import serializers

from users.models import User
from .utils import generate_save_user_token_url
from celery_tasks.email.tasks import send_verify_email
from .models import Address


class CreateUserSerializer(serializers.ModelSerializer):
    #声明校验字段【序列化 和 反序列化】
    password2=serializers.CharField(label='确认密码',write_only=True)
    sms_code=serializers.CharField(label='短信验证码',write_only=True)
    allow=serializers.CharField(label='同意协议',write_only=True)
    token=serializers.CharField(label='jwt token',read_only=True)
    class Meta:
        model=User
        fields=['token','id','username','password','password2','sms_code','mobile','allow']
        extra_kwargs={
            'username':{
                'min_length':5,
                'max_length':20,
                'error_messages':{
                    'min_length':'仅允许5-20个字符的用户名',
                    'max_length':'仅允许5-20个字符的用户名',

                }
            },
            'password':{
                'write_only':True,
                'min_length':8,
                'max_length':20,
                'error_messages':{
                    'min_length':'仅允许8-20个字符的密码',
                    'max_length':'仅允许8-20个字符的密码',
                }
            }
        }
    def validate_allow(self,value):
        '''检验用户是否同意协议'''
        if value !='true':
            raise serializers.ValidationError('请同意用户协议')
        #原样返回
        return  value


    def validate_mobile(self,value):
        print(value)
        if not re.match(r'^1[3-9]\d{9}$',value):
            raise serializers.ValidationError('手机号格式错误')
        count=User.objects.filter(mobile=value).count()
        if count>0:
            raise serializers.ValidationError('手机号已注册')
        return value
    #自己动手校验用户名的唯一性


    #校验方法【validate 和 validate_字段名】
    def validate(self, attrs):
        #判断密码是否一致
        password=attrs.get('password')
        password2=attrs.get('password2')
        if password !=password2:
            raise serializers.ValidationError('密码和确认密码不一致！')
        #判断短信验证码是否正确
        #把用户提交的短信验证码和redis中保存的判断是否一致
        sms_code=attrs.get('sms_code')
        mobile = attrs.get("mobile")
        #创建链接redis的对象获取redis数据
        redis=get_redis_connection('verify')
        real_code=redis.get('sms_%s'% mobile)
        #从redis提取的数据都是bytes类型数据
        #转变类型的时候，同时校验real_code是否存还在因为之前存储进去redis的时候设置了存储时间
        try :
            real_code=real_code.decode()
        except Exception as e:
            raise serializers.ValidationError('短信验证码不存在或已经过期了')
        if real_code !=sms_code:
            raise serializers.ValidationError('短信验证码错误')
        return attrs
    #模型操作【create 和update】
    def create(self, validated_data):
        '''

        :param validated_data: 校验完成以后的用户提交的数据
        :return:
        '''

        #移除数据库模型类中不存在的属性
        del validated_data['password2']
        del validated_data['sms_code']
        del validated_data['allow']

        #使用模型create保存数据
        #super().create事先已经实现号的添加数据功能，是ModelSerializer的方法
        user=super().create(validated_data)
        #通模型类设置密码加密
        user.set_password(validated_data['password'])
        user.save()
        #注册成了，使用jwt保存登录状态
        from rest_framework_jwt.settings import api_settings

        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)

        user.token=token

        #返回模型
        return user


class EmailSerializer(serializers.ModelSerializer):



    '''用户邮箱序列化器'''
    class Meta:
        model=User
        fields=['id','email']
        extra_kwargs={
            'email':{
                'required':True
            }
        }

    def update(self, instance, validated_data):
        instance.email=validated_data['email']
        instance.save()

     #生成验证邮箱的链接【instance就是当强已经登录的用户】
        verify_url=generate_save_user_token_url(instance)

        #异步发送邮件
        send_verify_email.delay(instance.email,verify_url)
        return instance


class UserAddressSerializer(serializers.ModelSerializer):
    #声明字段
    #用于显示给客户端浏览器的地址信息【增加__str__方法的关联
    province=serializers.StringRelatedField(read_only=True)
    city=serializers.StringRelatedField(read_only=True)
    district=serializers.StringRelatedField(read_only=True)

    #设置保存的数据表的id信息【取消关联】
    province_id =serializers.IntegerField(label='省ID',required=True)
    city_id=serializers.IntegerField(label='市ID',required=True)
    district_id=serializers.IntegerField(label='区ID',required=True)

    class Meta:
        model=Address
        #表示排除掉列表中设置的字段，剩下的字段都要在序列化器里使用
        exclude=['user','is_deleted','create_time','update_time']
    #校验数据
    def validate_mobile(self,value):
        '''验证手机号'''
        if not re.match(r'^1[3-9]\d{9}$',value):
            raise serializers.ValidationError('手机号格式错误')
        return value
    # def  update(self, instance, validated_data):
    #
    #     instance.title=validated_data.get('title',instance.title)
    #     instance.save()
    #     return instance
    def create(self, validated_data):
        #获取当前登录用户
        #self.context就是实例化序列化器时的第三个参数，可以允许视图那边传递数据到序列化器中
        #self.context 提供了三个参数：view视图对象， request请求对象，format参数格式
        #在GenericAPIView里面的get_serializer方法中默认帮我们把视图对象传递到了序列化器中
        #当前已经登录的用户保存到过过滤后的数据中
        validated_data['user']=self.context['request'].user
        #调用原来的drf的序列化器的保存方法
        return super().create(validated_data)

class AddressTitleSerializer(serializers.ModelSerializer):
    '''地址标题'''
    class Meta:
        model=Address
        fields=('title',)
